using Microsoft.Extensions.Logging;
using System.IO;
using DocumentCreationSystem.Models;

namespace DocumentCreationSystem.Services;

/// <summary>
/// 简化的文件监控服务实现
/// </summary>
public class SimpleFileMonitorService : IFileMonitorService
{
    private readonly ILogger<SimpleFileMonitorService> _logger;
    private readonly Dictionary<int, MonitorStatus> _monitoringProjects;
    private readonly Dictionary<int, FileSystemWatcher> _watchers;

    public SimpleFileMonitorService(ILogger<SimpleFileMonitorService> logger)
    {
        _logger = logger;
        _monitoringProjects = new Dictionary<int, MonitorStatus>();
        _watchers = new Dictionary<int, FileSystemWatcher>();
    }

    public event EventHandler<FileChangeEventArgs>? FileChanged;
    public event EventHandler<FileChangeEventArgs>? FileCreated;
    public event EventHandler<FileChangeEventArgs>? FileDeleted;
    public event EventHandler<FileRenamedEventArgs>? FileRenamed;
    public event EventHandler<MonitorErrorEventArgs>? MonitorError;

    public async Task<bool> StartMonitoringAsync(int projectId, string projectPath)
    {
        try
        {
            if (_monitoringProjects.ContainsKey(projectId))
            {
                _logger.LogInformation($"项目 {projectId} 已在监控中");
                return true;
            }

            if (!Directory.Exists(projectPath))
            {
                _logger.LogWarning($"项目路径不存在: {projectPath}");
                return false;
            }

            var watcher = new FileSystemWatcher(projectPath)
            {
                IncludeSubdirectories = true,
                NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName,
                Filter = "*.*"
            };

            watcher.Changed += (sender, e) => OnFileChanged(projectId, e);
            watcher.Created += (sender, e) => OnFileCreated(projectId, e);
            watcher.Deleted += (sender, e) => OnFileDeleted(projectId, e);
            watcher.Renamed += (sender, e) => OnFileRenamed(projectId, e);
            watcher.Error += (sender, e) => OnError(projectId, e);

            watcher.EnableRaisingEvents = true;
            _watchers[projectId] = watcher;

            var status = new MonitorStatus
            {
                ProjectId = projectId,
                ProjectPath = projectPath,
                IsActive = true,
                StartTime = DateTime.Now
            };
            _monitoringProjects[projectId] = status;

            _logger.LogInformation($"开始监控项目 {projectId}: {projectPath}");
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"启动项目监控失败: {projectId}");
            return false;
        }
    }

    public async Task<bool> StopMonitoringAsync(int projectId)
    {
        try
        {
            if (_watchers.TryGetValue(projectId, out var watcher))
            {
                watcher.EnableRaisingEvents = false;
                watcher.Dispose();
                _watchers.Remove(projectId);
            }

            if (_monitoringProjects.TryGetValue(projectId, out var status))
            {
                status.IsActive = false;
                _monitoringProjects.Remove(projectId);
            }

            _logger.LogInformation($"停止监控项目: {projectId}");
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"停止项目监控失败: {projectId}");
            return false;
        }
    }

    public async Task StopAllMonitoringAsync()
    {
        try
        {
            var projectIds = _watchers.Keys.ToList();
            foreach (var projectId in projectIds)
            {
                await StopMonitoringAsync(projectId);
            }
            _logger.LogInformation("停止所有项目监控");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "停止所有监控失败");
        }
    }

    public bool IsMonitoring(int projectId)
    {
        return _monitoringProjects.ContainsKey(projectId) && 
               _monitoringProjects[projectId].IsActive;
    }

    public List<int> GetMonitoringProjects()
    {
        return _monitoringProjects.Keys.ToList();
    }

    public async Task<bool> TriggerFileSyncAsync(int projectId, string filePath)
    {
        try
        {
            // 简化实现：直接触发文件变更事件
            var args = new FileChangeEventArgs
            {
                ProjectId = projectId,
                FilePath = filePath,
                FileName = Path.GetFileName(filePath),
                ChangeType = FileChangeType.Modified,
                Timestamp = DateTime.Now
            };

            FileChanged?.Invoke(this, args);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"触发文件同步失败: {filePath}");
            return false;
        }
    }

    public async Task<int> ScanAndSyncProjectAsync(int projectId)
    {
        try
        {
            if (!_monitoringProjects.TryGetValue(projectId, out var status))
            {
                return 0;
            }

            var files = Directory.GetFiles(status.ProjectPath, "*.*", SearchOption.AllDirectories)
                .Where(f => IsValidFile(f))
                .ToList();

            foreach (var file in files)
            {
                await TriggerFileSyncAsync(projectId, file);
            }

            _logger.LogInformation($"扫描同步项目 {projectId}，处理 {files.Count} 个文件");
            return files.Count;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"扫描同步项目失败: {projectId}");
            return 0;
        }
    }

    public void SetFileFilter(int projectId, List<string> includePatterns, List<string> excludePatterns)
    {
        if (_monitoringProjects.TryGetValue(projectId, out var status))
        {
            status.FilterConfig.IncludePatterns = includePatterns;
            status.FilterConfig.ExcludePatterns = excludePatterns;
            _logger.LogInformation($"设置项目 {projectId} 文件过滤器");
        }
    }

    private void OnFileChanged(int projectId, FileSystemEventArgs e)
    {
        if (!IsValidFile(e.FullPath)) return;

        var args = new FileChangeEventArgs
        {
            ProjectId = projectId,
            FilePath = e.FullPath,
            FileName = e.Name ?? "",
            ChangeType = FileChangeType.Modified,
            Timestamp = DateTime.Now
        };

        FileChanged?.Invoke(this, args);
    }

    private void OnFileCreated(int projectId, FileSystemEventArgs e)
    {
        if (!IsValidFile(e.FullPath)) return;

        var args = new FileChangeEventArgs
        {
            ProjectId = projectId,
            FilePath = e.FullPath,
            FileName = e.Name ?? "",
            ChangeType = FileChangeType.Created,
            Timestamp = DateTime.Now
        };

        FileCreated?.Invoke(this, args);
    }

    private void OnFileDeleted(int projectId, FileSystemEventArgs e)
    {
        var args = new FileChangeEventArgs
        {
            ProjectId = projectId,
            FilePath = e.FullPath,
            FileName = e.Name ?? "",
            ChangeType = FileChangeType.Deleted,
            Timestamp = DateTime.Now
        };

        FileDeleted?.Invoke(this, args);
    }

    private void OnFileRenamed(int projectId, RenamedEventArgs e)
    {
        var args = new FileRenamedEventArgs
        {
            ProjectId = projectId,
            OldFilePath = e.OldFullPath,
            NewFilePath = e.FullPath,
            OldFileName = e.OldName ?? "",
            NewFileName = e.Name ?? "",
            Timestamp = DateTime.Now
        };

        FileRenamed?.Invoke(this, args);
    }

    private void OnError(int projectId, ErrorEventArgs e)
    {
        var args = new MonitorErrorEventArgs
        {
            ProjectId = projectId,
            ErrorMessage = e.GetException().Message,
            Exception = e.GetException(),
            Timestamp = DateTime.Now
        };

        MonitorError?.Invoke(this, args);
        _logger.LogError(e.GetException(), $"文件监控错误，项目: {projectId}");
    }

    private bool IsValidFile(string filePath)
    {
        var extension = Path.GetExtension(filePath).ToLowerInvariant();
        var validExtensions = new[] { ".docx", ".txt", ".md" };
        return validExtensions.Contains(extension);
    }

    public void Dispose()
    {
        StopAllMonitoringAsync().Wait();
    }
}
